import Request from 'luch-request';
import systemConfig from '@/common/config';
import { user, system } from '@/store';
import * as u from '@/tool/function/util';
import { encryptSM4, decryptSM2, decryptSM4 } from '@/common/utils/util';
import { signatureGenerate } from '@/common/utils/signatureUtil';
import qs from 'qs';
// 存储由于 token 过期导致 失败的请求
let expiredRequestArr: any[] = [];
let expiredReqArr: any[] = [];
// 避免频繁发送更新
let firstRequre = true;
// 避免频繁发送更新
let firstReq = true;
// 正在进行中的请求列表
let reqList = [] as any; // 如果某个api存在这个数组里，说明该api暂时无法再次请求
export const service = new Request({
  baseURL: '',
  method: 'POST',
  timeout: systemConfig.apiTimeout || 60000,
  // 自定义params 处理函数
  paramsSerializer: (params?: object) => {
    return qs.stringify(params);
  },
  // 返回当前请求的task, options。请勿在此处修改options。非必填
  getTask: (task, options) => {
    if (systemConfig.repeatEnabled) {
      const header = options.header as any;
      if (header) {
        const dataSign = header['x-bifang-session'];
        const repeatEnabled = header?.repeatEnabled;
        if (repeatEnabled === 'true') {
          for (let i = 0; i < reqList.length; i++) {
            if (reqList[i] === dataSign) {
              task.abort();
              return;
            }
          }
          reqList.push(dataSign);
        }
      }
    }
  },
});
/**
 * 允许某个请求可以继续进行
 * @param {array} reqList 全部请求列表
 * @param {string} url 请求地址
 */
const allowRequest = function (reqList: any, url: string) {
  if (url && reqList.length > 0) {
    for (let i = 0; i < reqList.length; i++) {
      if (reqList[i] === url) {
        reqList.splice(i, 1);
        break;
      }
    }
  } else {
    reqList = [];
  }
};
service.interceptors.request.use(
  async (config) => {
    // 可使用async await 做异步操作
    await init();
    // 获取请求头参数
    const { signature, timestamp, dataSign } = signatureGenerate(config);
    config.header = {
      ...config.header,
      appId: systemConfig.appId + '',
      signature: signature,
      timestamp: timestamp + '',
      'x-bifang-session': dataSign,
      'x-encrty-split': systemConfig.splitFlag
    };
    if (!config.header['content-type']) {
      config.header['content-type'] = 'application/json';
    }
    // 在发送请求之前做些什么 token
    const token = user.accesstoken;
    if (token) {
      (<any>config.header)[systemConfig.accessTokenName] = token;
    }

    return config;
  },
  (error) => {
    // 可使用async await 做异步操作
    if (systemConfig.repeatEnabled) {
      const header = error.header as any;
      let dataSign = "";
      if(header){
        dataSign = header['x-bifang-session'];
      }
      // 增加延迟，相同请求不得在短时间内重复发送
      setTimeout(() => {
        allowRequest(reqList, dataSign);
      }, 100);
    }
    return Promise.reject(error);
  }
);
service.interceptors.response.use(
  async (response) => {
    console.log(response);
    // 对响应数据做点什么
    let res = response?.data;
    if (!res) {
      res = response;
    }
    const encrtyStr = response.header['x-encrty-enabled'];

    const code = res.code;
    if (code && code !== 0 && code !== 200) {
      let errMsg = res.message;
      if (code === 401) {
        uni.showModal({
          title: '未登录',
          content: '当前用户已登出，请尝试重新登录后再操作。',
          confirmText: '重新登录',
          success: () => {
            user.setToken(null, null);
            uni.reLaunch({ url: systemConfig.loginPath });
          },
        });
      } else if (code === 403) {
        if (systemConfig.errorModel === 'modal') {
          uni.showModal({
            title: '系统提示',
            content: errMsg || '没有操作权限！',
            showCancel: false,
          });
        } else {
          uni.showToast({
            title: errMsg || '没有操作权限！',
            icon: 'none',
            duration: 4000,
          });
        }
      } else if (code === 456) {
        let refreshToken = user.refreshToken;
        if (!refreshToken) {
          refreshToken = u.getCookie(systemConfig.localRefreshTokenName);
        }
        await user.setToken(null, refreshToken);
        if (!refreshToken) {
          uni.showModal({
            title: '未登录',
            content: '当前用户已登出，请尝试重新登录后再操作。',
            confirmText: '重新登录',
            success: () => {
              user.setToken(null, null);
              uni.reLaunch({ url: systemConfig.loginPath });
            },
          });
        } else {
          /**
           * refreshToken 为封装的有关更新 token 的相关操作
           */
          if (firstRequre) {
            let res = updateTokenByRefreshToken(response.config);
            return res;
          } else {
            //如果当前已经是处于刷新token的状态，就将请求置于请求队列中，这个队列会在刷新token的回调中执行，由于new关键子存在声明提升，所以不用顾虑会有请求没有处理完的情况，这段添加请求的程序一定会在刷新token的回调执行之前执行的
            return new Promise((resolve) => {
              //这里加入的是一个promise的解析函数，将响应的config配置对应解析的请求函数存到requests中，等到刷新token回调后再执行
              expiredRequestArr.push(() => {
                resolve(service.request(response.config));
              });
            });
          }
        }
      } else if (code === 457) {
        if (systemConfig.errorModel === 'modal') {
          uni.showModal({
            title: '系统提示',
            content: errMsg || '请刷新页面！',
            showCancel: false,
          });
        } else {
          uni.showToast({
            title: errMsg || '请刷新页面！',
            icon: 'none',
            duration: 4000,
          });
        }
      } else if (code === 404) {
        if (systemConfig.errorModel === 'modal') {
          uni.showModal({
            title: '系统提示',
            content: errMsg || '请求资源不存在',
            showCancel: false,
          });
        } else {
          uni.showToast({
            title: errMsg || '请求资源不存在',
            icon: 'none',
            duration: 4000,
          });
        }
      } else if (code === 408) {
        if (systemConfig.errorModel === 'modal') {
          uni.showModal({
            title: '系统提示',
            content: '请求超时！',
            showCancel: false,
          });
        } else {
          uni.showToast({
            title: '请求超时！',
            icon: 'none',
            duration: 4000,
          });
        }
      } else if (code === 500) {
        if (systemConfig.errorModel === 'modal') {
          uni.showModal({
            title: '系统提示',
            content: errMsg || '接口返回错误500',
            showCancel: false,
          });
        } else {
          uni.showToast({
            title: errMsg || '接口返回错误500',
            icon: 'none',
            duration: 4000,
          });
        }
      } else if (code < 0) {
        if (systemConfig.errorModel === 'modal') {
          uni.showModal({
            title: '系统提示',
            content: errMsg || '请求服务异常',
            showCancel: false,
          });
        } else {
          uni.showToast({
            title: errMsg || '请求服务异常',
            icon: 'none',
            duration: 4000,
          });
        }
      }
      return Promise.reject(res);
    } else {
      if (systemConfig.repeatEnabled) {
        const header = response?.header as any;
        let dataSign = '' as any;
        if (header) {
          dataSign = header['x-bifang-session'];
        }

        // 增加延迟，相同请求不得在短时间内重复发送
        setTimeout(() => {
          allowRequest(reqList, dataSign);
        }, 100);
      }

      if (encrtyStr === 'true') {
        //解密报文
        let result = res.result;
        if (result) {
          let secretKey = '';
          let decrytStr = decryptSM2(result, secretKey);
          try {
            res.result = JSON.parse(decrytStr);
          } catch (e) {
            res.result = decrytStr;
          }

          return res;
        }
        return res;
      }
      return res;
    }
  },
  (error) => {
    /*  对响应错误做点什么 （statusCode !== 200）*/
    console.log(error);
    let code = error.statusCode;
    let errMsg = error.errMsg;
    if (systemConfig.repeatEnabled) {
      if (errMsg.indexOf('fail abort') != -1) {
        console.error('请求中断:' + error?.config?.url);
        return Promise.reject(error);
      } else {
        const header = error.header as any;
        let dataSign = '';
        if (header) {
          dataSign = header['x-bifang-session'];
        }
        // 增加延迟，相同请求不得在短时间内重复发送
        setTimeout(() => {
          allowRequest(reqList, dataSign);
        }, 100);
      }
    }

    // 对响应错误做点什么
    if (errMsg.indexOf('timeout') != -1) {
      if (systemConfig.errorModel === 'modal') {
        uni.showModal({
          title: '系统提示',
          content: '网络超时！',
          showCancel: false,
        });
      } else {
        uni.showToast({
          title: '网络超时！',
          icon: 'none',
          duration: 4000,
        });
      }
    } else if (errMsg == 'Network Error') {
      if (systemConfig.errorModel === 'modal') {
        uni.showModal({
          title: '系统提示',
          content: '网络连接错误',
          showCancel: false,
        });
      } else {
        uni.showToast({
          title: '网络连接错误',
          icon: 'none',
          duration: 4000,
        });
      }
    } else {
      if (code) {
        if (code === 401) {
          uni.showModal({
            title: '未登录',
            content: '当前用户已登出，请尝试重新登录后再操作。',
            confirmText: '重新登录',
            success: () => {
              user.setToken(null, null);

              uni.reLaunch({ url: systemConfig.loginPath });
            },
          });
        } else if (code === 403) {
          if (systemConfig.errorModel === 'modal') {
            uni.showModal({
              title: '系统提示',
              content: error.errMsg || '没有操作权限！',
              showCancel: false,
            });
          } else {
            uni.showToast({
              title: errMsg || '没有操作权限！',
              icon: 'none',
              duration: 4000,
            });
          }
        } else if (code === 457) {
          if (systemConfig.errorModel === 'modal') {
            uni.showModal({
              title: '系统提示',
              content: errMsg || '请刷新页面！',
              showCancel: false,
            });
          } else {
            uni.showToast({
              title: errMsg || '请刷新页面！',
              icon: 'none',
              duration: 4000,
            });
          }
        } else if (code === 404) {
          if (systemConfig.errorModel === 'modal') {
            uni.showModal({
              title: '系统提示',
              content: errMsg || '请求资源不存在',
              showCancel: false,
            });
          } else {
            uni.showToast({
              title: errMsg || '请求资源不存在',
              icon: 'none',
              duration: 4000,
            });
          }
        } else if (code === 408) {
          if (systemConfig.errorModel === 'modal') {
            uni.showModal({
              title: '系统提示',
              content: '请求超时！',
              showCancel: false,
            });
          } else {
            uni.showToast({
              title: '请求超时！',
              icon: 'none',
              duration: 4000,
            });
          }
        } else if (code === 500) {
          if (systemConfig.errorModel === 'modal') {
            uni.showModal({
              title: '系统提示',
              content: errMsg || '接口返回错误500',
              showCancel: false,
            });
          } else {
            uni.showToast({
              title: errMsg || '接口返回错误500',
              icon: 'none',
              duration: 4000,
            });
          }
        } else if (code !== 200) {
          if (systemConfig.errorModel === 'modal') {
            uni.showModal({
              title: '系统提示',
              content: errMsg || '请求服务异常',
              showCancel: false,
            });
          } else {
            uni.showToast({
              title: errMsg || '请求服务异常',
              icon: 'none',
              duration: 4000,
            });
          }
        }
      } else {
        if (systemConfig.errorModel === 'modal') {
          uni.showModal({
            title: '系统提示',
            content: '请求服务器无响应！',
            showCancel: false,
          });
        } else {
          uni.showToast({
            title: '请求服务器无响应！',
            icon: 'none',
            duration: 4000,
          });
        }
      }
    }

    return Promise.reject(error);
  }
);
/**
 * 利用 refreshToken 更新当前使用的 token
 */
const updateTokenByRefreshToken = (reqConfig: any) => {
  return new Promise((resolve) => {
    firstRequre = false;
    let config: any = {};
    let headers = { 'func-code': 'base0018', cryptoEnabled: 'true' };
    config.header = headers;
    let params = {} as any;
    params[systemConfig.refreshTokenName] = user.refreshToken;
    let url = systemConfig.baseUrl+systemConfig.commonUrl + 'base0018';
    service
      .post(url, params, config)
      .then((res: any) => {
        const result = res.result;
        user.setToken(result.accessToken, result.refreshToken);
        if (result.secretKey) {
          u.setCookie('USERSECRET', encryptSM4(JSON.stringify(result.secretKey), system.defaultSM4Key));
        }
        user.setUserSecret(result.secretKey);
        /**
         * 当获取了最新的 refreshToken, accessToken 后
         * 重新发起之前失败的请求
         */
        expiredRequestArr.forEach((run) => run());
        expiredRequestArr = [];
        resolve(service.request(reqConfig));
      })
      .catch(() => {
        uni.showModal({
          title: '未登录',
          content: '当前用户已登出，请尝试重新登录后再操作。',
          confirmText: '重新登录',
          success: () => {
            user.setToken(null, null);
            uni.reLaunch({ url: systemConfig.loginPath });
          },
        });
      })
      .finally(() => {
        firstRequre = true;
      });
  });
};

// 请求库类型导出，方便后面的 API 模块调用
export default class http {
  /** post 请求
   * @param  {接口地址} url
   * @param  {请求参数} data
   * @param  {参数} opts
   */
  static async post(url: string, data?: object, config?: any) {
    return service.post(url, data, config);
  }
  /** get 请求
   * @param  {接口地址} url
   * @param  {请求参数} data
   * @param  {参数} opts
   */
  static async get(url: string, data?: any, config?: any) {
    let param = { url: url, method: 'GET', params: data, header: config.header, timeout: config.timeout } as any;
    return service.request(param);
  }
}

const init = async () => {
  if (!user.defaultSM2PublicKey && !user.defaultSM4Key) {
    let secretStr = u.getCookie('USERSECRET');
    if (secretStr) {
      let secret = JSON.parse(decryptSM4(secretStr, system.defaultSM4Key));
      await user.setUserSecret(secret);
    } else {
      u.delCookie(systemConfig.localTokenName);
      u.delCookie(systemConfig.localRefreshTokenName);
    }
  }
  if (!system.appCryptoFlag) {
    await system.setAppCryptoFlag(true);
    let config: any = {};
    let headers = { 'func-code': 'base0017' };
    config.header = headers;
    let url = systemConfig.baseUrl +systemConfig.commonUrl + 'base0017';
    await http.post(url, { appId: encryptSM4(systemConfig.appId + '', system.defaultSM4Key) }, config);
  }
  if (systemConfig.refreshTokenEnabled) {
    let refreshToken = user.refreshToken;
    if (!refreshToken && !system.zlbFlag) {
      refreshToken = u.getCookie(systemConfig.localRefreshTokenName);
      user.setToken(u.getCookie(systemConfig.localTokenName), refreshToken);
    }
  } else {
    let accessToken = user.accesstoken;
    if (!accessToken && !system.zlbFlag) {
      accessToken = u.getCookie(systemConfig.localTokenName);
      user.setToken(accessToken, u.getCookie(systemConfig.localRefreshTokenName));
    }
  }
};
